home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / MacPerl / MPAEVTStream.cp < prev    next >
Encoding:
Text File  |  1995-02-19  |  12.0 KB  |  583 lines

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Standalone Perl
  3. File        :    MPConsole.cp    -    Console interface for GUSI
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: MPConsole.cp,v $
  8. *********************************************************************/
  9.  
  10. #include <GUSIFile_P.h>
  11.  
  12. #include "MPGlobals.h"
  13. #include "MPAEVTStream.h"
  14. #include "MPConsole.h"
  15.  
  16. #include <AEStream_CPlus.h>
  17.  
  18. extern "C" {
  19. #include <AESubDescs.h>
  20.  
  21. #include <ioctl.h>
  22. }
  23.  
  24. class MPAEVTSocket;                             // That's what this file's all about
  25.  
  26. class MPAEVTSocket : public Socket    {        
  27.     friend class MPAEVTSocketDomain;    
  28.     
  29.                     MPAEVTSocket(OSType key, Boolean input, Boolean output);
  30.                     
  31.     virtual         ~MPAEVTSocket();
  32.     
  33.     OSType                        key;
  34.     Handle                        inData;
  35.     Handle                        outData;
  36.     Boolean                        eof;
  37.     Boolean                        nonblocking;
  38.     Boolean                        needy;
  39.     MPAEVTSocket *                next;
  40.     MPAEVTSocket *             prev;
  41. public:
  42.     virtual int    read(void * buffer, int buflen);
  43.     virtual int write(void * buffer, int buflen);
  44.     virtual int    fcntl(unsigned int cmd, int arg);
  45.     virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  46.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  47.     virtual int    ioctl(unsigned int request, void *argp);
  48.     virtual int    isatty();
  49. };    
  50.  
  51. class MPAEVTSocketDomain : public FileSocketDomain {
  52.     friend class MPAEVTSocket;
  53.     
  54.     MPAEVTSocket *            Lookup(OSType key, Boolean input, Boolean output);
  55.     
  56.     MPAEVTSocket *            first;
  57.     OSType                    key;
  58.     OSType                    mode;
  59.     DescType                    saseClass;
  60.     DescType                    saseID;
  61.     AppleEvent                sase;
  62.     AEDesc                    target;
  63.     AEStream                    outputData;
  64.     AEDesc                    outputDirect;
  65.     short                        outputDataCount;
  66. public:
  67.     MPAEVTSocketDomain();
  68.     
  69.     virtual Boolean Yours(const GUSIFileRef & ref, Request request);
  70.     virtual Socket * open(const GUSIFileRef & ref, int oflag);
  71.     
  72.     void CollectOutput(AppleEvent * output);
  73.     void DistributeInput(const AppleEvent * input, long mode);
  74.     void KillInput();
  75.  
  76.     void         DoRead();
  77.     Boolean    MayRead();
  78.     
  79.     Boolean                    finish;
  80.     long                        received;
  81. };
  82.  
  83. MPAEVTSocketDomain    MPAEVTSockets;
  84.  
  85. #if !defined(powerc) && !defined(__powerc)
  86. #pragma segment MPAEVT
  87. #endif
  88.  
  89. /************************ MPAEVTSocket members ************************/
  90.  
  91. MPAEVTSocket::MPAEVTSocket(OSType key, Boolean input, Boolean output)
  92.     : key(key)
  93. {
  94.     eof        =    !input || MPAEVTSockets.mode == 'BATC';
  95.     inData    =    input ? NewHandle(0) : nil;
  96.     outData    =    output ? NewHandle(0) : nil;
  97.     
  98.     if (!MPAEVTSockets.first) {
  99.         MPAEVTSockets.first    = this;
  100.         next                        = this;
  101.         prev                        = this;
  102.     } else {
  103.         next                         = MPAEVTSockets.first;
  104.         prev                         = MPAEVTSockets.first->prev;
  105.         next->prev                = this;
  106.         prev->next                 = this;
  107.     }
  108. }
  109.  
  110. MPAEVTSocket::~MPAEVTSocket()
  111. {
  112.     if (outData)
  113.         if (GetHandleSize(outData)) {
  114.             AEDesc    desc ;
  115.             
  116.             desc.descriptorType = 'TEXT';
  117.             desc.dataHandle     = outData;
  118.             
  119.             if (key == '----')
  120.                 MPAEVTSockets.outputDirect    =    desc;
  121.             else {
  122.                 MPAEVTSockets.outputData.WriteKey(key);
  123.                 MPAEVTSockets.outputData.WriteDesc(desc);
  124.                 ++MPAEVTSockets.outputDataCount;
  125.                 AEDisposeDesc(&desc);
  126.             }
  127.         } else
  128.             DisposeHandle(outData);
  129.             
  130.     if (inData)
  131.         DisposeHandle(inData);
  132.     
  133.     if (next == this)
  134.         MPAEVTSockets.first    = nil;
  135.     else {
  136.         MPAEVTSockets.first    = next;
  137.         next->prev                = prev;
  138.         prev->next                = next;
  139.     }
  140. }
  141.  
  142. int MPAEVTSocket::fcntl(unsigned int cmd, int arg)
  143. {
  144.     switch (cmd)    {
  145.     case F_GETFL:
  146.         if (nonblocking)
  147.             return FNDELAY;
  148.         else
  149.             return 0;
  150.     case F_SETFL:
  151.         if (arg & FNDELAY)
  152.             nonblocking = true;
  153.         else
  154.             nonblocking = false;
  155.  
  156.         return 0;
  157.     default:
  158.         return GUSI_error(EOPNOTSUPP);
  159.     }
  160. }
  161.  
  162. int MPAEVTSocket::ioctl(unsigned int request, void *argp)
  163. {
  164.     switch (request)    {
  165.     case FIONBIO:
  166.         nonblocking    =    (Boolean) *(long *) argp;
  167.         
  168.         return 0;
  169.     case FIONREAD:
  170.         if (!inData)
  171.             return GUSI_error(ESHUTDOWN);
  172.         
  173.         *(unsigned long *) argp    = GetHandleSize(inData);
  174.         
  175.         return 0;
  176.     case FIOINTERACTIVE:
  177.         return 0;
  178.     default:
  179.         return GUSI_error(EOPNOTSUPP);
  180.     }
  181. }
  182.  
  183. int MPAEVTSocket::read(void * buffer, int buflen)
  184. {
  185.     if (!inData)
  186.         return GUSI_error(ESHUTDOWN);
  187.  
  188.     int    avail;
  189.     
  190.     while (1) {    
  191.         avail = int(GetHandleSize(inData));
  192.         
  193.         if (!avail)
  194.             if (eof)
  195.                 return 0;
  196.             else {
  197.                 needy = true;
  198.                 if (nonblocking)
  199.                     return GUSI_error(EWOULDBLOCK);
  200.                 else
  201.                     MPAEVTSockets.DoRead();
  202.             }
  203.         else
  204.             break;
  205.     }
  206.     
  207.     needy     = false;
  208.     buflen = min(avail, buflen);
  209.     
  210.     HLock(inData);
  211.     memcpy(buffer, *inData, buflen);
  212.     if (avail -= buflen)
  213.         memcpy(*inData, *inData+buflen, avail);
  214.     HUnlock(inData);
  215.     SetHandleSize(inData, avail);
  216.     
  217.     return buflen;
  218. }
  219.  
  220. int MPAEVTSocket::write(void * buffer, int buflen)
  221. {
  222.     if (!outData)
  223.         return GUSI_error(ESHUTDOWN);
  224.     else if (PtrAndHand(buffer, outData, buflen))
  225.         return GUSI_error(ENOMEM);
  226.     
  227.     return buflen;
  228. }
  229.  
  230. void MPAEVTSocket::pre_select(Boolean, Boolean, Boolean)
  231. {
  232.     needy = false;
  233. }
  234.  
  235. int MPAEVTSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  236. {
  237.     int        goodies     =     0;
  238.         
  239.     if (canRead)
  240.         if (inData)
  241.             if (*canRead = (GetHandleSize(inData) > 0 || eof))
  242.                 ++goodies;
  243.             else if (needy)
  244.                 MPAEVTSockets.DoRead();
  245.             else
  246.                 needy = true;
  247.         else
  248.             *canRead = false;
  249.     
  250.     if (canWrite)
  251.         if (*canWrite = (outData != nil))
  252.             ++goodies;
  253.     
  254.     if (exception)
  255.         *exception = false;
  256.     
  257.     return goodies;
  258. }
  259.  
  260. int MPAEVTSocket::isatty()
  261. {
  262.     return 1;
  263. }
  264.  
  265. /********************* MPAEVTSocketDomain members **********************/
  266.  
  267. #if !defined(powerc) && !defined(__powerc)
  268. #pragma force_active on
  269. #endif
  270.  
  271. MPAEVTSocketDomain::MPAEVTSocketDomain()
  272.     :    FileSocketDomain(AF_UNSPEC, true, false), finish(false), first(nil), received(0)
  273. {
  274.     outputData.OpenRecord(typeAERecord);
  275. }
  276.  
  277. Boolean MPAEVTSocketDomain::Yours(const GUSIFileRef & ref, FileSocketDomain::Request request)
  278. {
  279.     if (ref.spec || (request != willOpen))
  280.         return false;
  281.     
  282.     if (
  283.             (ref.name[4] | 0x20) == 's'
  284.         && (ref.name[5] | 0x20) == 't' 
  285.         && (ref.name[6] | 0x20) == 'd'
  286.     ) {
  287.         if (!gRemoteControl)
  288.             return false;
  289.             
  290.         switch (ref.name[7] | 0x20) {
  291.         case 'i':
  292.             key = '----';
  293.             
  294.             return (ref.name[8] | 0x20) == 'n' && !ref.name[9];
  295.         case 'o':
  296.             key = '----';
  297.             
  298.             return    (ref.name[8] | 0x20) == 'u' 
  299.                     && (ref.name[9] | 0x20) == 't' 
  300.                     && !ref.name[10];
  301.         case 'e':
  302.             key = 'diag';
  303.             
  304.             return     (ref.name[8] | 0x20) == 'r' 
  305.                     && (ref.name[9] | 0x20) == 'r' 
  306.                     && !ref.name[10];
  307.         default:
  308.             return false;
  309.         }
  310.     } else if (!strncmp(ref.name+4, "AEVT", 4))
  311.         switch (ref.name[8]) {
  312.         case 0:
  313.             key = '----';
  314.         
  315.             return true;
  316.         case ':':
  317.             key = '    ';
  318.             
  319.             int len = strlen(ref.name+9);
  320.             
  321.             memcpy(&key, ref.name+9, len < 4 ? len : 4);
  322.             
  323.             return true;
  324.         }
  325.     
  326.     return false;
  327. }
  328.  
  329. Socket * MPAEVTSocketDomain::open(const GUSIFileRef &, int flags)
  330. {
  331.     return Lookup(key, !(flags & O_WRONLY), (flags & 3) != 0);
  332. }
  333.  
  334. Boolean MPAEVTSocketDomain::MayRead()
  335. {
  336.     return mode == 'RCTL';
  337. }
  338.  
  339. void MPAEVTSocketDomain::DoRead()
  340. {
  341.     if (!MayRead())
  342.         KillInput();
  343.     else {    
  344.         long    oldReceived = received;
  345.         
  346.         if (sase.dataHandle) {
  347.             /* Send tickle event. Errors are probably deadly, as they case MacPerl to hang */
  348.             AppleEvent    tickle;
  349.             
  350.             if (AECreateAppleEvent(saseClass, saseID, &target, 0, 0, &tickle))
  351.                 goto waitForData;
  352.             
  353.             AEKeyword    key;
  354.             AEDesc        desc;
  355.             
  356.             for (long index = 1; !AEGetNthDesc(&sase, index++, typeWildCard, &key, &desc);) {
  357.                 AEPutParamDesc(&tickle, key, &desc);
  358.                 AEDisposeDesc(&desc);
  359.             }
  360.             
  361.             AESend(&tickle, &desc, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  362.             
  363.             AEDisposeDesc(&tickle);
  364.         }
  365.     waitForData:
  366.         while (!MPConsoleSpin(SP_STREAM_READ, 0) && oldReceived == received)
  367.             ;
  368.     }
  369. }
  370.  
  371. static void AEGetAttrOrParam(AEDesc * from, DescType keyword, void * into)
  372. {
  373.     Size         size;
  374.     DescType    type;
  375.  
  376.     if (AEGetAttributePtr(from, keyword, typeWildCard, &type, into, 4, &size))
  377.         if (!AEGetParamPtr(from, keyword, typeWildCard, &type, into, 4, &size))
  378.             AEDeleteParam(from, keyword);
  379. }
  380.  
  381. void MPAEVTSocketDomain::DistributeInput(const AppleEvent * input, long mode)
  382. {
  383.     AEDesc        desc;
  384.     AESubDesc    aes;
  385.     AESubDesc    item;
  386.     DescType        keyword;
  387.     
  388.     if (mode)
  389.         this->mode = mode;
  390.         
  391.     if (!AEGetParamDesc(input, 'INPT', typeAERecord, &desc)) {
  392.         AEDescToSubDesc(&desc, &aes);
  393.  
  394.         HLock(aes.dataHandle);
  395.         
  396.         long maxIndex = AECountSubDescItems(&aes);
  397.         
  398.         for (long index = 0; index++ < maxIndex; ) {
  399.             if (AEGetNthSubDesc(&aes, index, &keyword, &item))
  400.                 continue;
  401.                 
  402.             long                length;
  403.             
  404.             void *             data = AEGetSubDescData(&item, &length);
  405.             MPAEVTSocket * sock = Lookup(keyword, true, false);
  406.             
  407.             if (sock)
  408.                 if (AEGetSubDescType(&item) == typeNull)
  409.                     sock->eof = true;                
  410.                 else if (sock->inData && length)
  411.                     PtrAndHand(data, sock->inData, length);
  412.         }
  413.         
  414.         AEDisposeDesc(&desc);
  415.     }
  416.     
  417.     if (!mode) {
  418.         if (!AEGetParamDesc(input, '----', typeWildCard, &desc)) {
  419.             MPAEVTSocket * sock = Lookup('----', true, false);
  420.         
  421.             if (sock)
  422.                 if (desc.descriptorType == typeNull)
  423.                     sock->eof = true;
  424.                 else if (sock->inData) {
  425.                     HLock(desc.dataHandle);
  426.                     HandAndHand(desc.dataHandle, sock->inData);
  427.                 }
  428.         
  429.             AEDisposeDesc(&desc);
  430.         }
  431.     } else {
  432.         desc           = sase;
  433.         
  434.         if (AEGetParamDesc(input, 'SASE', typeAERecord, &sase)) 
  435.             sase = desc;
  436.         else {
  437.             if (desc.dataHandle)
  438.                 AEDisposeDesc(&desc);
  439.             desc = target;
  440.             if (AEGetAttributeDesc(input, keyAddressAttr, typeWildCard, &target))
  441.                 target = desc;
  442.             else if (desc.dataHandle)
  443.                 AEDisposeDesc(&desc);
  444.                 
  445.             AEGetAttrOrParam(&sase, keyEventClassAttr, &saseClass);
  446.             AEGetAttrOrParam(&sase, keyEventIDAttr, &saseID);
  447.         }
  448.     }
  449. }
  450.  
  451. void MPAEVTSocketDomain::KillInput()
  452. {
  453.     int                runs = 0;
  454.     MPAEVTSocket * sock = first;
  455.  
  456.     if (sock)
  457.         while ((runs += sock == first) < 2) {
  458.             if (sock->needy) 
  459.                 sock->eof = true;
  460.             
  461.             sock = sock->next;
  462.         }
  463. }
  464.  
  465. void MPAEVTSocketDomain::CollectOutput(AppleEvent * output)
  466. {
  467.     OSErr                err;
  468.     AEStream         want;
  469.     AEDesc            desc;
  470.     int                wantCount = 0;
  471.     int                runs = 0;
  472.     MPAEVTSocket * sock = first;
  473.     
  474.     desc.descriptorType = 'TEXT';
  475.     
  476.     want.OpenList();
  477.     
  478.     if (sock)
  479.         while ((runs += sock == first) < 2) {
  480.             if (sock->outData) {
  481.                 desc.dataHandle = sock->outData;
  482.                 if (sock->key == '----')
  483.                     if (!AEPutParamDesc(output, '----', &desc))
  484.                         SetHandleSize(sock->outData, 0);
  485.                     else 
  486.                         return;                            // This is sort of disastrous
  487.                 else if (outputData.WriteKey(sock->key) || outputData.WriteDesc(desc))                
  488.                     return;                                //     ... so is this.
  489.                 else 
  490.                     ++outputDataCount;
  491.             }
  492.             if (sock->inData && sock->needy)
  493.                 if (!want.WriteDesc(typeEnumerated, &sock->key, 4))
  494.                     ++wantCount;
  495.             
  496.             sock = sock->next;
  497.         }
  498.     
  499.     if (outputDirect.dataHandle) {
  500.         err = AEPutParamDesc(output, '----', &outputDirect);
  501.         AEDisposeDesc(&outputDirect);
  502.     
  503.         if (err)
  504.             return;
  505.     }
  506.     
  507.     err = outputData.CloseRecord() || outputData.Close(&desc);
  508.     
  509.     AEStream_Open(&outputData);
  510.     outputData.OpenRecord(typeAERecord);
  511.     
  512.     if (outputDataCount) {
  513.         outputDataCount = 0;
  514.         if (!err) {
  515.             err = AEPutParamDesc(output, 'OUTP', &desc);
  516.             AEDisposeDesc(&desc);
  517.             
  518.             if (err)
  519.                 return;    // Death before Dishonour
  520.         } else
  521.             return;
  522.     }
  523.         
  524.     if (!want.CloseList() && wantCount) {
  525.         if (!want.Close(&desc)) {
  526.             AEPutParamDesc(output, 'WANT', &desc);
  527.             AEDisposeDesc(&desc);
  528.         } 
  529.     } else
  530.         want.Close();
  531.     
  532.     if (sock)    
  533.         for (runs = 0; (runs += sock == first) < 2; sock = sock->next) 
  534.             if (sock->outData) 
  535.                 SetHandleSize(sock->outData, 0);
  536. }
  537.  
  538. MPAEVTSocket * MPAEVTSocketDomain::Lookup(OSType key, Boolean input, Boolean output)
  539. {
  540.     int                runs = 0;
  541.     MPAEVTSocket * sock = first;
  542.     
  543.     if (sock)
  544.         while ((runs += sock == first) < 2)
  545.             if (sock->key == key) {
  546.                 if (input && !sock->inData)
  547.                     sock->inData = NewHandle(0);
  548.                 if (output && !sock->outData)
  549.                     sock->outData = NewHandle(0);
  550.                 
  551.                 return sock;
  552.             } else
  553.                 sock = sock->next;
  554.     
  555.     return new MPAEVTSocket(key, input, output);
  556. }
  557.  
  558. /********************* Interface routines **********************/
  559.  
  560. pascal OSErr Relay(const AppleEvent * inData, AppleEvent * outData, long refCon)
  561. {
  562.     ++MPAEVTSockets.received;
  563.     
  564.     if (inData)
  565.         MPAEVTSockets.DistributeInput(inData, refCon);
  566.     if (outData)
  567.         MPAEVTSockets.CollectOutput(outData);
  568.         
  569.     return noErr;
  570. }
  571.  
  572. pascal void FlushAEVTs(AppleEvent * outData)
  573. {
  574.     if (outData)
  575.         MPAEVTSockets.CollectOutput(outData);
  576.     else {
  577.         MPAEVTSockets.finish = true;
  578.         MPAEVTSockets.DoRead();
  579.         MPAEVTSockets.finish = false;
  580.     }
  581. }
  582.  
  583.